/*
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package commandhandlers;

import input.IRCCommand;
import interfaces.CommandHandler;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TimeZone;

import javax.mail.MessagingException;
import javax.mail.internet.AddressException;

import main.Bot;
import main.CommonMethods;
import main.Main;
import main.UserCentral;

import org.apache.log4j.Logger;
import org.jibble.pircbot.Colors;

import output.IRCOutput;
import timers.AlarmTimer;
import tools.BCrypt;
import tools.InputType;
import tools.MailClient;
import tools.StringTools;
import tools.UtopiaTime;
import botobjects.ContactInfo;
import botobjects.Stats;
import botobjects.Status;
import botobjects.User;
import database.DBConnectionFactory;

/**
 * This class takes care of functions related to the User
 * 
 * 
 */
public class UserHandler extends CommandHandler {
   private static class HoFItem {
	  public String user;
	  public int amount;

	  public HoFItem(final String user, final int amount) {
		 this.user = user;
		 this.amount = amount;
	  }
   }

   private static UserHandler INSTANCE = null;

   /**
    * Registers seen-information
    * 
    * @param nick
    * @param channel
    */
   public static void addLastSeen(final String nick, final String channel) {
	  PreparedStatement ps = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection().prepareStatement("DELETE FROM seen WHERE nick = ?");
		 ps.setString(1, nick);
		 ps.executeUpdate();

		 try {
			ps.close();
		 } catch (final Exception e) {
		 }

		 ps = DBConnectionFactory.getConnectionHandler().getConnection().prepareStatement("INSERT INTO seen VALUES(?,?,?)");
		 ps.setString(1, nick);
		 ps.setTimestamp(2, new Timestamp(GregorianCalendar.getInstance().getTimeInMillis()));
		 ps.setString(3, channel);
		 ps.executeUpdate();
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
   }

   /**
    * Registers user activity (the user talking where the bot can see it)
    * 
    * @param nick
    */
   public static void addUserActivity(final String mainNick, final String currentNick) {
	  checkForMessage(mainNick, currentNick);
	  BotHandler.checkForWait(currentNick);
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT * FROM idle WHERE mainnick = ?");
		 ps.setString(1, mainNick);
		 rs = ps.executeQuery();

		 if (rs.next()) {
			try {
			   ps.close();
			} catch (final Exception e) {
			}

			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("UPDATE idle SET lastactivity = ? WHERE mainnick = ?");
			ps.setTimestamp(1, new Timestamp(GregorianCalendar.getInstance().getTimeInMillis()));
			ps.setString(2, mainNick);
			ps.executeUpdate();
		 } else {
			try {
			   ps.close();
			} catch (final Exception e) {
			}

			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("INSERT INTO idle VALUES(?,?,?,?,?,?,?,?)");
			ps.setString(1, mainNick);
			ps.setTimestamp(2, new Timestamp(GregorianCalendar.getInstance().getTimeInMillis()));
			ps.setTimestamp(3, new Timestamp(GregorianCalendar.getInstance().getTimeInMillis()));
			ps.setTimestamp(4, new Timestamp(GregorianCalendar.getInstance().getTimeInMillis()));
			ps.setTimestamp(5, new Timestamp(GregorianCalendar.getInstance().getTimeInMillis()));
			ps.setTimestamp(6, new Timestamp(GregorianCalendar.getInstance().getTimeInMillis()));
			ps.setTimestamp(7, new Timestamp(GregorianCalendar.getInstance().getTimeInMillis()));
			ps.setTimestamp(8, new Timestamp(GregorianCalendar.getInstance().getTimeInMillis()));
			ps.executeUpdate();
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
   }

   /**
    * Checks whether there are messages waiting for the user
    * 
    * @param recipient
    * @param currentNick
    */
   public static void checkForMessage(final String recipient, final String currentNick) {
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT * FROM message WHERE recipient = ?");
		 ps.setString(1, recipient);
		 rs = ps.executeQuery();
		 while (rs.next()) {
			String msg = rs.getString("sender") + " sends you this message: " + rs.getString("message");
			Bot.getInstance().sendMessage(currentNick, msg);
		 }

		 try {
			ps.close();
		 } catch (final Exception e) {
		 }

		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("DELETE FROM message WHERE recipient = ?");
		 ps.setString(1, recipient);
		 ps.executeUpdate();
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
   }

   /**
    * Removes an alarm for the user
    * 
    * @param user
    * @return
    */
   public static List<String> delAlarm(final String user) {
	  List<String> out = new LinkedList<String>();
	  PreparedStatement ps = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection().prepareStatement("DELETE FROM alarm WHERE mainnick = ?");
		 ps.setString(1, user);
		 ps.executeUpdate();

		 Bot.getInstance().getTimerHandler().removeAlarmTimer(user);
		 out.add("Alarm removed");
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   public static final UserHandler getInstance() {
	  if (INSTANCE == null) {
		 INSTANCE = new UserHandler();
	  }
	  return INSTANCE;
   }

   /**
    * Adds a new nick to the users list of nicks
    * 
    * @param newNick
    * @param mainNick
    * @return
    */
   public static List<String> linkNick(final String newNick, final String mainNick) {
	  List<String> out = new LinkedList<String>();
	  if (!StringTools.validateInput(InputType.NICKNAME, newNick))
		 return out;
	  PreparedStatement ps = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection().prepareStatement("INSERT INTO nickname VALUES(?,?)");
		 ps.setString(1, newNick);
		 ps.setString(2, mainNick);
		 if (ps.executeUpdate() == 1) {
			out.add(newNick + " has been linked to you");
		 }

		 try {
			ps.close();
		 } catch (final Exception e) {
		 }

		 // In case someone used the nick before and it registered in the
		 // seen list
		 ps = DBConnectionFactory.getConnectionHandler().getConnection().prepareStatement("DELETE FROM seen WHERE nick = ?");
		 ps.setString(1, newNick);
		 ps.executeUpdate();
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   public static final UserHandler newInstance() {
	  INSTANCE = null;
	  return getInstance();
   }

   /**
    * Checks if the specified nick is already taken by someone else, or served for the bot or something similar
    * 
    * @param nick
    * @return
    */
   public static boolean nickIsFree(final String nick) {
	  if (nick.equals(Bot.getInstance().getNick()) || Bot.getInstance().workersContain(nick) || nick.equalsIgnoreCase("all")
			|| nick.equalsIgnoreCase("notice"))
		 return false;
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  boolean out = false;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT * FROM nickname WHERE name = ?");
		 ps.setString(1, nick);
		 rs = ps.executeQuery();
		 out = !rs.next();
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
			Logger.getLogger("Error").error("", e);
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Checks if the user owns the nick he/she is currently on
    * 
    * @param currentNick
    * @param mainNick
    * @return
    */
   public static boolean ownsNick(final String currentNick, final String mainNick) {
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  boolean out = false;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT * FROM nickname WHERE name = ? AND mainnick = ?");
		 ps.setString(1, currentNick);
		 ps.setString(2, mainNick);
		 rs = ps.executeQuery();
		 out = rs.next();
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Sends an email-to-sms to the specified user
    * 
    * @param user
    * @param subject
    * @param content
    * @param sender
    * @return
    */
   public static List<String> sendSMS(final String user, final String subject, final String content, final String sender) {
	  List<String> out = new LinkedList<String>();
	  PreparedStatement ps = null;
	  PreparedStatement ps2 = null;
	  ResultSet rs = null;
	  ResultSet rs2 = null;
	  try {
		 if ("".equals(user)) {
			ps = DBConnectionFactory.getConnectionHandler().getConnection().prepareStatement("SELECT * FROM sms");
		 } else {
			ps = DBConnectionFactory.getConnectionHandler().getConnection().prepareStatement("SELECT * FROM sms WHERE nick = ?");
			ps.setString(1, user);
		 }
		 rs = ps.executeQuery();

		 ps2 = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT * FROM smssettings WHERE id = 0");
		 rs2 = ps2.executeQuery();

		 if (rs2.next()) {
			final MailClient mc = new MailClient(rs2.getString("server"), rs2.getString("username"), rs2.getString("password"),
				  rs2.getInt("port"));
			final ArrayList<String> to = new ArrayList<String>();
			while (rs.next()) {
			   to.add(rs.getString("mail"));
			}
			try {
			   mc.sendMail(sender, to, subject, content);
			   out.add("Sms sent" + ("".equals(user) ? "" : " to " + user));
			} catch (final AddressException e) {
			   Logger.getLogger("Error").error("", e);
			   out.add(user + "'s address is incorrect");
			} catch (final MessagingException e) {
			   Logger.getLogger("Error").error("", e);
			   out.add("Sms failed");
			}
		 } else {
			out.add("No sms settings were found");
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs2.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps2.close();
		 } catch (final Exception e) {
		 }
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Adds a bot account for the specified user
    */
   public static List<String> setPassword(final String user, final String password, final boolean isDefaultPassword) {
	  List<String> out = new LinkedList<String>();
	  PreparedStatement ps = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("DELETE FROM botaccount WHERE name = ?");
		 ps.setString(1, user);
		 ps.executeUpdate();

		 try {
			ps.close();
		 } catch (final Exception e) {
		 }

		 ps = DBConnectionFactory.getConnectionHandler().getConnection().prepareStatement("INSERT INTO botaccount VALUES(?,?,?)");
		 ps.setString(1, user);
		 ps.setString(2, BCrypt.hashpw(password, BCrypt.gensalt()));
		 ps.setBoolean(3, isDefaultPassword);
		 if (ps.executeUpdate() != 1)
			return out;
		 if (isDefaultPassword) {
			out.add(user + "'s botaccount reset with the default password \"password\"");
		 } else {
			out.add("Your Bot/forum agent account info: " + user + "/" + password);
			out.add("The password is irreversably encrypted in the database, so if you forget it, set a new one");
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   private UserHandler() {
   }

   /**
    * Adds a message that will be sent to another online or offline user
    * 
    * @param command
    * @param sender
    * @return
    */
   private List<String> addMessage(final String recipient, final String message, final String sender) {
	  List<String> out = new LinkedList<String>();
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("INSERT INTO message VALUES(default,?,?,?,?)");
		 ps.setString(1, recipient);
		 ps.setString(2, sender);
		 ps.setString(3, message);
		 ps.setTimestamp(4, new Timestamp(GregorianCalendar.getInstance().getTimeInMillis()));
		 ps.executeUpdate();

		 try {
			ps.close();
		 } catch (final Exception e) {
		 }

		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT id FROM " + "message WHERE recipient = ? AND message = ? ORDER BY timesent DESC");
		 ps.setString(1, recipient);
		 ps.setString(2, message);
		 rs = ps.executeQuery();
		 if (rs.next()) {
			out.add("Message added - use id number " + rs.getInt("id") + " if you want to remove it");
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Confirms whether the sms addy is working or not
    * 
    * @param user
    * @param status
    * @return
    */
   private List<String> confirmSMSAddress(final String user, final boolean status) {
	  List<String> out = new LinkedList<String>();
	  PreparedStatement ps = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("UPDATE sms SET confirmed = ? WHERE nick = ?");
		 ps.setBoolean(1, status);
		 ps.setString(2, user);
		 ps.executeUpdate();

		 out.add("Confirmed that your sms addy is " + (status ? "" : "not ") + "working");
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Removes a message
    * 
    * @param id
    * @param user
    * @return
    */
   private List<String> delMessage(final int id, final String user) {
	  List<String> out = new LinkedList<String>();
	  PreparedStatement ps = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("DELETE FROM message WHERE id = ? AND sender = ?");
		 ps.setInt(1, id);
		 ps.setString(2, user);
		 if (ps.executeUpdate() == 1) {
			out.add("Message " + id + " removed");
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Returns information about the user's alarm
    * 
    * @param user
    * @return
    */
   private List<String> getAlarm(final String user) {
	  List<String> out = new LinkedList<String>();
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT * FROM alarm WHERE mainnick = ?");
		 ps.setString(1, user);
		 rs = ps.executeQuery();
		 if (rs.next()) {
			Timestamp time = rs.getTimestamp("settime");
			String temp = UtopiaTime.compareTimes(time.getTime());

			out.add(rs.getString("mainnick") + "'s alarm is set to go off in: " + temp + " with the message: "
				  + rs.getString("message"));
		 } else {
			out.add("No alarm set for " + user);
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Returns information about the time at which the alarm will go off for the user
    * 
    * @param user
    * @param tz
    * @return
    */
   private List<String> getAlarmTime(final String user, final TimeZone tz) {
	  List<String> out = new LinkedList<String>();
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT * FROM alarm WHERE mainnick = ?");
		 ps.setString(1, user);
		 rs = ps.executeQuery();

		 if (rs.next()) {
			String pattern = "EEE, MMM d, H:mm:ss";
			SimpleDateFormat sdf = new SimpleDateFormat(pattern, Locale.US);
			sdf.setTimeZone(tz);
			String out1 = sdf.format(new java.util.Date(rs.getTimestamp("settime").getTime()));
			String temp = rs.getString("mainnick") + "'s alarm is set for " + out1 + " with the message: "
				  + rs.getString("message");

			out.add(Colors.RED + temp);
		 } else {
			out.add("No alarm set for " + user);
		 }

	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Returns information about when the bot last saw the specified user
    * 
    * @param nick
    * @return
    */
   private List<String> getLastSeen(final String nick) {
	  List<String> out = new LinkedList<String>();
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT * FROM seen WHERE " + "nick = ?");
		 ps.setString(1, nick);
		 rs = ps.executeQuery();
		 if (rs.next()) {
			String msg = Colors.OLIVE + rs.getString("message") + " " + Colors.BLUE
				  + UtopiaTime.compareTimes(rs.getTimestamp("seentime").getTime()) + " ago";
			out.add(msg);
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Returns the user's (or all users) registered sms addy
    * 
    * @param user
    * @return
    */
   private List<String> getSMSAddress(final String user) {
	  List<String> out = new LinkedList<String>();
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 if ("".equals(user)) {
			ps = DBConnectionFactory.getConnectionHandler().getConnection().prepareStatement("SELECT * FROM sms");
		 } else {
			ps = DBConnectionFactory.getConnectionHandler().getConnection().prepareStatement("SELECT * FROM sms WHERE nick = ?");
			ps.setString(1, user);
		 }
		 rs = ps.executeQuery();

		 if ("".equals(user)) {
			String output = "People with registered sms addys: ";
			while (rs.next()) {
			   if (output.length() > 300) {
				  out.add(output);
				  output = "";
			   }
			   output += rs.getString("nick") + (rs.getBoolean("confirmed") ? "(C)" : "") + " | ";
			}
			if (output.length() > 0) {
			   out.add(output);
			}
		 } else {
			while (rs.next()) {
			   out.add(user + "'s current sms address: " + rs.getString("mail") + " - Confirmed working: "
					 + rs.getBoolean("confirmed"));
			}
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Returns the hall of fame for stats
    * 
    * @return
    */
   private List<String> getStatsHoF() {
	  List<String> out = new LinkedList<String>();
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection().prepareStatement("SELECT * FROM actions");
		 rs = ps.executeQuery();

		 final Map<String, HoFItem> stats = new HashMap<String, HoFItem>();
		 while (rs.next()) {
			if (stats.containsKey(rs.getString("actiontype"))) {
			   int value = stats.get(rs.getString("actiontype")).amount;
			   if (value < rs.getInt("amount")) {
				  stats.put(rs.getString("actiontype"), new HoFItem(rs.getString("performer"), rs.getInt("amount")));
			   }
			} else {
			   stats.put(rs.getString("actiontype"), new HoFItem(rs.getString("performer"), rs.getInt("amount")));
			}
		 }
		 out.add("HoF:");
		 for (final Entry<String, HoFItem> e : stats.entrySet()) {
			out.add(Colors.OLIVE + e.getKey() + ": " + Colors.BLUE + e.getValue().user + " (" + e.getValue().amount + ")");
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Returns the time the user last said something that wasn't a command
    * 
    * @param nick
    * @return
    */
   private Long getUserLastActive(final String nick) {
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  Long out = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT lastactivity FROM idle WHERE mainnick = ?");
		 ps.setString(1, nick);
		 rs = ps.executeQuery();

		 if (rs.next()) {
			out = rs.getTimestamp("lastactivity").getTime();
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   @Override
   public void handle(final IRCCommand command, final IRCOutput output) {
   }

   public void handleAddnotification(final IRCCommand command, final IRCOutput out) {
	  if (command.get(1).equals("army")) {
		 out.addOutput(setSMSNotification(UserCentral.getInstance().getOnlineUser(command.getSender()), 0, true));
	  } else if (command.get(1).equals("alarm")) {
		 out.addOutput(setSMSNotification(UserCentral.getInstance().getOnlineUser(command.getSender()), 2, true));
	  } else if (command.get(1).equals("wave")) {
		 out.addOutput(setSMSNotification(UserCentral.getInstance().getOnlineUser(command.getSender()), 1, true));
	  } else if (command.get(1).equals("orders")) {
		 out.addOutput(setSMSNotification(UserCentral.getInstance().getOnlineUser(command.getSender()), 3, true));
	  }
   }

   public void handleAdduser(final IRCCommand command, final IRCOutput out) {
	  if (UserCentral.getInstance().onlineUserIsAdmin(command.getSender(), command.getChannel()) && command.size() == 2) {
		 if (nickIsFree(command.get(1)) && new User(command.get(1)).saveToDB()) {
			out.addOutput("User added successfully");
		 } else {
			out.addOutput("Nick already busy");
		 }
	  }
   }

   public void handleAlarm(final IRCCommand command, final IRCOutput out) {
	  String user = UserCentral.getInstance().getOnlineUser(command.getSender());
	  if (command.size() == 1) {
		 out.addOutput(getAlarm(user));
	  } else if ((command.isDouble(1) || command.isInt(1)) && command.size() >= 2) {
		 Double delay = Double.parseDouble(command.get(1)) * 3600000;
		 out.addOutput(setAlarm(user, delay.longValue(), command.size() == 2 ? "" : command.getPartialMessage(2, command.size())));
	  } else if (command.size() > 3) {
		 SimpleDateFormat sdf = new SimpleDateFormat("yyyy MMM d HH:mm", Locale.US);
		 sdf.setTimeZone(TimeZone.getTimeZone("GMT" + CommonMethods.getUserTimeZone(user)));
		 try {
			Calendar cal = Calendar.getInstance();
			Date date = sdf.parse(cal.get(Calendar.YEAR) + " " + command.getPartialMessage(1, 4));
			if (date.getTime() <= GregorianCalendar.getInstance().getTimeInMillis()) {
			   cal.add(Calendar.YEAR, 1);
			   date = sdf.parse(cal.get(Calendar.YEAR) + " " + command.getPartialMessage(1, 4));
			}
			out.addOutput(setAlarm(user, date.getTime() - GregorianCalendar.getInstance().getTimeInMillis(),
				  command.getPartialMessage(4, command.size())));
		 } catch (final Exception e) {
			out.addOutput("Incorrect date. Example: October 28 18:00");
		 }
	  } else {
		 user = CommonMethods.getUserFromDBFuzzyMatching(command.get(1));
		 if (!"".equals(user)) {
			out.addOutput(getAlarm(user));
		 }
	  }
   }

   public void handleAlarmtime(final IRCCommand command, final IRCOutput out) {
	  if (command.size() == 1) {
		 TimeZone tz = TimeZone.getTimeZone("GMT"
			   + CommonMethods.getUserTimeZone(UserCentral.getInstance().getOnlineUser(command.getSender())));
		 out.addOutput(getAlarmTime(UserCentral.getInstance().getOnlineUser(command.getSender()), tz));
	  } else {
		 String user = CommonMethods.getUserFromDBFuzzyMatching(command.get(1));
		 if ("".equals(user))
			return;
		 TimeZone tz = TimeZone.getTimeZone("GMT"
			   + CommonMethods.getUserTimeZone(UserCentral.getInstance().getOnlineUser(command.getSender())));
		 out.addOutput(getAlarmTime(user, tz));
	  }
   }

   public void handleAuthenticate(final IRCCommand command, final IRCOutput out) {
	  if (Main.getBotSettings().requirePasswordAuth()
			&& command.getSender().equals(command.getChannel())
			&& (UserCentral.getInstance().getMainchanUsers().contains(command.getSender()) || UserCentral.getInstance()
				  .getAdminchanUsers().contains(command.getSender())) && command.size() == 2) {
		 String mainnick = CommonMethods.getUserFromDB(command.getSender(), false);
		 if (CommonMethods.loginBotAccount(mainnick, command.get(1))) {
			if (CommonMethods.hasDefaultBotAccount(mainnick, command.get(1))) {
			   out.addOutput("You're using the default password, and so the bot will now check if you're on an"
					 + " identified nick. If you aren't, authentication will fail.");
			   out.addOutput("When/if you get successfully authenticated, please set a new password with setpassword <password>");
			   Bot.getInstance().doStatusCheck(command.getSender());
			} else {
			   UserCentral.getInstance().authenticateUser(command.getSender(), command.getChannel());
			   Bot.getInstance().sendWelcomeMessage(command.getSender());
			}
		 }
	  } else if (UserCentral.getInstance().getMainchanUsers().contains(command.getSender())
			|| UserCentral.getInstance().getAdminchanUsers().contains(command.getSender())) {
		 Bot.getInstance().doStatusCheck(command.getSender());
	  }
   }

   public void handleConfirmsms(final IRCCommand command, final IRCOutput out) {
	  String user = UserCentral.getInstance().getOnlineUser(command.getSender());
	  if (command.size() == 1) {
		 out.addOutput(confirmSMSAddress(user, true));
	  } else if (command.size() == 2) {
		 if (command.get(1).equals("false")) {
			out.addOutput(confirmSMSAddress(user, false));
		 } else {
			out.addOutput(confirmSMSAddress(user, true));
		 }
	  }
   }

   public void handleContacts(final IRCCommand command, final IRCOutput out) {
	  if (command.size() > 3 && "add".equals(command.get(1))) {
		 if ("name".equalsIgnoreCase(command.get(2))) {
			ContactInfo ci = new ContactInfo(UserCentral.getInstance().getOnlineUser(command.getSender()));
			ci.setName(command.getPartialMessage(3, command.size()));
			if (ci.saveToDB()) {
			   out.addOutput("Name saved successfully");
			}
		 } else if ("country".equalsIgnoreCase(command.get(2))) {
			ContactInfo ci = new ContactInfo(UserCentral.getInstance().getOnlineUser(command.getSender()));
			ci.setCountry(command.getPartialMessage(3, command.size()));
			if (ci.saveToDB()) {
			   out.addOutput("Country saved successfully");
			}
		 } else if ("sms".equalsIgnoreCase(command.get(2))) {
			ContactInfo ci = new ContactInfo(UserCentral.getInstance().getOnlineUser(command.getSender()));
			ci.setSmsAddy(command.get(3));
			if (ci.saveToDB()) {
			   out.addOutput("Sms saved successfully");
			}
		 } else {
			ContactInfo ci = new ContactInfo(UserCentral.getInstance().getOnlineUser(command.getSender()));
			Map<String, String> map = new HashMap<String, String>();
			map.put(command.get(2), command.getPartialMessage(3, command.size()));
			ci.setMisc(map);
			if (ci.saveToDB()) {
			   out.addOutput(command.get(2) + " saved successfully");
			}
		 }
	  } else if (command.size() > 4 && "add".equals(command.get(2))
			&& !"".equals(CommonMethods.getUserFromDB(command.get(1), false))
			&& UserCentral.getInstance().onlineUserIsAdmin(command.getSender(), command.getChannel())) {
		 if ("name".equalsIgnoreCase(command.get(3))) {
			ContactInfo ci = new ContactInfo(CommonMethods.getUserFromDB(command.get(1), false));
			ci.setName(command.getPartialMessage(4, command.size()));
			if (ci.saveToDB()) {
			   out.addOutput("Name saved successfully");
			}
		 } else if ("country".equalsIgnoreCase(command.get(3))) {
			ContactInfo ci = new ContactInfo(CommonMethods.getUserFromDB(command.get(1), false));
			ci.setCountry(command.getPartialMessage(4, command.size()));
			if (ci.saveToDB()) {
			   out.addOutput("Country saved successfully");
			}
		 } else if ("sms".equalsIgnoreCase(command.get(3))) {
			ContactInfo ci = new ContactInfo(CommonMethods.getUserFromDB(command.get(1), false));
			ci.setSmsAddy(command.get(4));
			if (ci.saveToDB()) {
			   out.addOutput("Sms saved successfully");
			}
		 } else {
			ContactInfo ci = new ContactInfo(CommonMethods.getUserFromDB(command.get(1), false));
			Map<String, String> map = new HashMap<String, String>();
			map.put(command.get(3), command.getPartialMessage(4, command.size()));
			ci.setMisc(map);
			if (ci.saveToDB()) {
			   out.addOutput(command.get(3) + " saved successfully");
			}
		 }
	  } else if (command.size() > 2 && "remove".equals(command.get(1))) {
		 if ("name".equalsIgnoreCase(command.get(2))) {
			out.addOutput(removeContactInfo("realname", UserCentral.getInstance().getOnlineUser(command.getSender())));
		 } else if ("country".equalsIgnoreCase(command.get(2))) {
			out.addOutput(removeContactInfo("country", UserCentral.getInstance().getOnlineUser(command.getSender())));
		 } else if ("sms".equalsIgnoreCase(command.get(2))) {
			out.addOutput(removeSMSAddress(UserCentral.getInstance().getOnlineUser(command.getSender())));
		 } else {
			out.addOutput(removeMiscContactInfo(command.get(2), UserCentral.getInstance().getOnlineUser(command.getSender())));
		 }
	  } else if (command.size() > 3 && "remove".equals(command.get(2))
			&& !"".equals(CommonMethods.getUserFromDB(command.get(1), false))
			&& UserCentral.getInstance().onlineUserIsAdmin(command.getSender(), command.getChannel())) {
		 if ("name".equalsIgnoreCase(command.get(3))) {
			out.addOutput(removeContactInfo("realname", CommonMethods.getUserFromDB(command.get(1), false)));
		 } else if ("country".equalsIgnoreCase(command.get(3))) {
			out.addOutput(removeContactInfo("country", CommonMethods.getUserFromDB(command.get(1), false)));
		 } else if ("sms".equalsIgnoreCase(command.get(3))) {
			out.addOutput(removeSMSAddress(CommonMethods.getUserFromDB(command.get(1), false)));
		 } else {
			out.addOutput(removeMiscContactInfo(command.get(3), CommonMethods.getUserFromDB(command.get(1), false)));
		 }
	  } else if (command.size() == 2) {
		 String searchFor = CommonMethods.getUserFromDBFuzzyMatching(command.get(1));
		 if ("".equals(searchFor)) {
			ContactInfo ci = ContactInfo.getContactInfo(command.get(1));
			if (ci != null) {
			   out.addOutput(ci.getIRCOutput(0));
			}
		 } else {
			ContactInfo ci = ContactInfo.getContactInfo(searchFor);
			if (ci != null) {
			   out.addOutput(ci.getIRCOutput(0));
			}
		 }
	  } else {
		 String searchFor = UserCentral.getInstance().getOnlineUser(command.getSender());
		 if (!"".equals(searchFor)) {
			ContactInfo ci = ContactInfo.getContactInfo(searchFor);
			if (ci != null) {
			   out.addOutput(ci.getIRCOutput(0));
			}
		 }
	  }
   }

   public void handleDst(final IRCCommand command, final IRCOutput out) {
	  String user = UserCentral.getInstance().getOnlineUser(command.getSender());
	  String setTo = "off";
	  if (command.size() == 2 && command.get(1).equals("on")) {
		 setTo = "on";
	  } else if (command.size() == 3 && (command.get(2).equals("on") || command.get(2).equals("off"))
			&& UserCentral.getInstance().onlineUserIsAdmin(command.getSender(), command.getChannel())) {
		 user = CommonMethods.getUserFromDB(command.get(1), false);
		 setTo = command.get(2);
	  }
	  if (!"".equals(user)) {
		 out.addOutput(setDST(user, setTo));
	  }
   }

   public void handleEndalarm(final IRCCommand command, final IRCOutput out) {
	  String user = UserCentral.getInstance().getOnlineUser(command.getSender());
	  out.addOutput(delAlarm(user));
   }

   public void handleHof(final IRCCommand command, final IRCOutput out) {
	  out.addOutput(getStatsHoF());
   }

   public void handleIdle(final IRCCommand command, final IRCOutput out) {
	  if (command.size() == 2) {
		 String user = CommonMethods.getUserFromDB(command.get(1), false);
		 if (!"".equals(user)) {
			Long lastActivity = getUserLastActive(user);
			if (lastActivity == null)
			   return;
			String time = UtopiaTime.compareTimes(lastActivity);
			out.addOutput(Colors.BLUE + user + Colors.OLIVE + " has been idle for " + Colors.BLUE + time);
		 }
	  }
   }

   public void handleIdlelist(final IRCCommand command, final IRCOutput out) {
	  out.addOutput(listIdleTime());
   }

   public void handleInfo(final IRCCommand command, final IRCOutput out) {
	  Bot.getInstance().sendWelcomeMessage(command.getSender());
   }

   public void handleLinknick(final IRCCommand command, final IRCOutput out) {
	  if (command.size() == 2) {
		 String user = UserCentral.getInstance().getOnlineUser(command.getSender());
		 if (ownsNick(command.getSender(), user)) {
			if (nickIsFree(command.get(1))) {
			   out.addOutput(linkNick(command.get(1), user));
			   out.addOutput("Please link the nick with nickserv too, to avoid identify theft (/ns link nick)");
			} else {
			   out.addOutput("That nick is already taken or invalid");
			}
		 } else {
			out.addOutput("You're not the owner of your current nick");
		 }
	  }
   }

   public void handleListmessages(final IRCCommand command, final IRCOutput out) {
	  String senderMain = UserCentral.getInstance().getOnlineUser(command.getSender());
	  out.addOutput(listMessages("".equals(senderMain) ? command.getSender() : senderMain));
   }

   public void handleMessage(final IRCCommand command, final IRCOutput out) {
	  if (command.size() > 2) {
		 if ("all".equalsIgnoreCase(command.get(1))) {
			String senderMain = UserCentral.getInstance().getOnlineUser(command.getSender());
			for (User user : User.getUsers()) {
			   if (!user.getMainNick().equals(senderMain)) {
				  addMessage(user.getMainNick(), command.getPartialMessage(2, command.size()),
						("".equals(senderMain) ? command.getSender() : senderMain));
			   }
			}
			out.addOutput("Messages added - check listmessages for ids");
		 } else {
			String recipient = CommonMethods.getUserFromDB(command.get(1), false);
			if (!"".equals(recipient)) {
			   command.set(1, recipient);
			}
			String user = UserCentral.getInstance().getOnlineUser(command.getSender());
			out.addOutput(addMessage(command.get(1), command.getPartialMessage(2, command.size()),
				  ("".equals(user) ? command.getSender() : user)));
		 }
	  }
   }

   public void handleNicklist(final IRCCommand command, final IRCOutput out) {
	  if (command.size() == 1) {
		 User user = User.getUser(UserCentral.getInstance().getOnlineUser(command.getSender()));
		 if (user == null)
			return;
		 String output = "Linked nicks: ";
		 for (String nick : user.getNickList()) {
			if (output.length() > 350) {
			   out.addOutput(output);
			   output = "";
			}
			output += nick + ",";
		 }
		 if (output.length() > 0) {
			out.addOutput(output);
		 }
	  } else {
		 String mainNick = CommonMethods.getUserFromDBFuzzyMatching(command.get(1));
		 if (!"".equals(mainNick)) {
			User user = User.getUser(mainNick);
			if (user == null)
			   return;
			String output = "Linked nicks: ";
			for (String nick : user.getNickList()) {
			   if (output.length() > 350) {
				  out.addOutput(output);
				  output = "";
			   }
			   output += nick + ",";
			}
			if (output.length() > 0) {
			   out.addOutput(output);
			}
		 }
	  }
   }

   public void handleRegister(final IRCCommand command, final IRCOutput out) {
	  if (command.getChannel().equals(Main.getBotSettings().getMainChannel()) && Main.getBotSettings().usersMayRegister()) {
		 if (nickIsFree(command.getSender()) && new User(command.getSender()).saveToDB()) {
			out.addOutput("You have been successfully registered. Please authenticate");
		 } else {
			out.addOutput("Registration failed. Nick is busy or the database isn't working");
		 }
	  }
   }

   public void handleRemovemessage(final IRCCommand command, final IRCOutput out) {
	  if (command.size() == 2) {
		 if (command.isInt(1)) {
			out.addOutput(delMessage(Integer.parseInt(command.get(1)),
				  UserCentral.getInstance().getOnlineUser(command.getSender())));
		 } else {
			out.addOutput("No message with that id");
		 }
	  }
   }

   public void handleRemovenotification(final IRCCommand command, final IRCOutput out) {
	  if (command.get(1).equals("army")) {
		 out.addOutput(setSMSNotification(UserCentral.getInstance().getOnlineUser(command.getSender()), 0, false));
	  } else if (command.get(1).equals("alarm")) {
		 out.addOutput(setSMSNotification(UserCentral.getInstance().getOnlineUser(command.getSender()), 2, false));
	  } else if (command.get(1).equals("wave")) {
		 out.addOutput(setSMSNotification(UserCentral.getInstance().getOnlineUser(command.getSender()), 1, false));
	  } else if (command.get(1).equals("orders")) {
		 out.addOutput(setSMSNotification(UserCentral.getInstance().getOnlineUser(command.getSender()), 3, false));
	  }
   }

   public void handleRemoveuser(final IRCCommand command, final IRCOutput out) {
	  if (UserCentral.getInstance().onlineUserIsAdmin(command.getSender(), command.getChannel()) && command.size() > 1) {
		 String user = CommonMethods.getUserFromDB(command.get(1), false);
		 if ("".equals(user)) {
			out.addOutput("User doesn't exist");
		 } else if (User.deleteFromDB(user)) {
			out.addOutput("User removed successfully");
		 }
	  }
   }

   public void handleResetuser(final IRCCommand command, final IRCOutput out) {
	  String user = CommonMethods.getUserFromDB(command.get(1), false);
	  if (command.size() > 1 || UserCentral.getInstance().onlineUserIsAdmin(command.getSender(), command.getChannel())) {
		 out.addOutput(setPassword(user, "password", true));
	  }
   }

   public void handleSeen(final IRCCommand command, final IRCOutput out) {
	  if (command.size() > 1) {
		 List<String> main = UserCentral.getInstance().getMainchanUsers();
		 List<String> admin = UserCentral.getInstance().getAdminchanUsers();
		 String nick = CommonMethods.getUserFromDB(command.get(1), false);
		 for (String u : main) {
			String userNick = u;
			String mainNick = CommonMethods.getUserFromDB(userNick, false);
			if (userNick.equals(command.get(1)) || nick.equals(mainNick) && !"".equals(nick)) {
			   out.addOutput("That user is already in " + Main.getBotSettings().getMainChannel() + " under the nick " + userNick);
			   return;
			}
		 }
		 for (String u : admin) {
			String userNick = u;
			String mainNick = CommonMethods.getUserFromDB(userNick, false);
			if (userNick.equals(command.get(1)) || nick.equals(mainNick) && !"".equals(nick)) {
			   if (command.getChannel().equals(Main.getBotSettings().getAdminChannel())) {
				  out.addOutput("That user is already in " + Main.getBotSettings().getAdminChannel() + " under the nick "
						+ userNick);
			   } else if (UserCentral.getInstance().onlineUserIsAdmin(command.getSender(), command.getChannel())) {
				  out.addOutput("That user is already in " + Main.getBotSettings().getAdminChannel() + " under the nick "
						+ userNick);
			   }
			   return;
			}
		 }
		 if ("".equals(nick)) {
			out.addOutput(getLastSeen(command.get(1)));
		 }
		 out.addOutput(getLastSeen(nick));
	  }
   }

   public void handleSetmainnick(final IRCCommand command, final IRCOutput out) {
	  String user = UserCentral.getInstance().getOnlineUser(command.getSender());
	  if (command.size() == 1) {
		 out.addOutput("You did not input a new nick");
	  } else {
		 if (ownsNick(command.getSender(), user) && ownsNick(command.get(1), user)) {
			ContactInfo ci = new ContactInfo(user);
			ci.setNewMainNick(command.get(1));
			if (ci.saveToDB()) {
			   UserCentral.getInstance().unauthenticateUser(command.getSender());
			   out.addOutput(Colors.NORMAL + "Your main nick was changed to " + Colors.BLUE + command.get(1) + Colors.NORMAL
					 + ". Please reauthenticate");
			}
		 } else {
			out.addOutput("You can only change to linked nicks");
		 }
	  }
   }

   public void handleSetpassword(final IRCCommand command, final IRCOutput out) {
	  String user = UserCentral.getInstance().getOnlineUser(command.getSender());
	  if (command.size() > 1 && command.getChannel().equals(command.getSender())) {
		 out.addOutput(setPassword(user, command.get(1), false));
	  }
   }

   public void handleSetstatus(final IRCCommand command, final IRCOutput out) {
	  if (command.size() > 1) {
		 String user = UserCentral.getInstance().getOnlineUser(command.getSender());
		 if (new Status(user, command.getFullMessage(), GregorianCalendar.getInstance().getTimeInMillis()).saveToDB()) {
			out.addOutput("Status message set");
		 }
	  }
   }

   public void handleSettimezone(final IRCCommand command, final IRCOutput out) {
	  String user = UserCentral.getInstance().getOnlineUser(command.getSender());
	  if (command.size() == 2 && command.isDouble(1)) {
		 double tz = Double.parseDouble(command.get(1));
		 if (tz < 14 && tz > -13) {
			ContactInfo ci = new ContactInfo(user);
			ci.setTimeZone(tz);
			if (ci.saveToDB()) {
			   out.addOutput("Timezone saved");
			}
		 }
	  } else if (command.size() == 3 && command.isDouble(2)
			&& UserCentral.getInstance().onlineUserIsAdmin(command.getSender(), command.getChannel())) {
		 double tz = Double.parseDouble(command.get(2));
		 user = CommonMethods.getUserFromDB(command.get(1), false);
		 if (tz < 14 && tz > -13 && !"".equals(user)) {
			ContactInfo ci = new ContactInfo(user);
			ci.setTimeZone(tz);
			if (ci.saveToDB()) {
			   out.addOutput("Timezone saved");
			}
		 }
	  }
   }

   public void handleSms(final IRCCommand command, final IRCOutput out) {
	  if (command.size() == 1) {
		 out.addOutput(getSMSAddress(UserCentral.getInstance().getOnlineUser(command.getSender())));
	  } else if (command.size() == 2) {
		 if (command.get(1).equals("all")
			   && UserCentral.getInstance().onlineUserIsAdmin(command.getSender(), command.getChannel())) {
			out.addOutput(getSMSAddress(""));
		 }
		 String user = CommonMethods.getUserFromDB(command.get(1), false);
		 if ("".equals(user))
			return;
		 out.addOutput(getSMSAddress(user));
	  } else if (command.size() > 2) {
		 String user = CommonMethods.getUserFromDB(command.get(1), false);
		 if ("".equals(user))
			return;
		 String message = "";
		 for (int i = 2; i < command.size(); ++i) {
			message += command.get(i) + " ";
		 }
		 message = message.trim();
		 out.addOutput(sendSMS("all".equals(user) ? "" : user, message, "",
			   UserCentral.getInstance().getOnlineUser(command.getSender())));
	  }
   }

   public void handleStats(final IRCCommand command, final IRCOutput out) {
	  String user = UserCentral.getInstance().getOnlineUser(command.getSender());
	  if (command.size() == 1) {
		 List<Stats> stats = Stats.getStats(user);
		 if (!stats.isEmpty()) {
			out.addOutput(stats.get(0).getIRCOutput(0));
		 }
	  } else {
		 user = CommonMethods.getUserFromDBFuzzyMatching(command.get(1));
		 List<Stats> stats = Stats.getStats(user);
		 if (!stats.isEmpty()) {
			out.addOutput(stats.get(0).getIRCOutput(0));
		 }
	  }
   }

   public void handleStatus(final IRCCommand command, final IRCOutput out) {
	  String user = UserCentral.getInstance().getOnlineUser(command.getSender());
	  if (command.size() == 1) {
		 for (Status status : Status.getStatus(user)) {
			out.addOutput(status.getIRCOutput(0));
		 }
	  } else {
		 user = CommonMethods.getUserFromDBFuzzyMatching(command.get(1));
		 if (!"".equals(user)) {
			for (Status status : Status.getStatus(user)) {
			   out.addOutput(status.getIRCOutput(0));
			}
		 }
	  }
   }

   public void handleUnlinknick(final IRCCommand command, final IRCOutput out) {
	  if (command.size() == 2) {
		 String mainNick = UserCentral.getInstance().getOnlineUser(command.getSender());
		 if (ownsNick(command.getSender(), mainNick)) {
			if (command.get(1).equals("all") && command.getSender().equals(mainNick)) {
			   out.addOutput(unlinkNick(command.get(1), command.getSender()));
			} else if (ownsNick(command.get(1), mainNick) && !command.get(1).equals(mainNick)) {
			   out.addOutput(unlinkNick(command.get(1), mainNick));
			}
		 }
	  }
   }

   /**
    * Lists the time the different users have been idle, which is defined as the time they have not said anything that wasn't a
    * command
    * 
    * @return
    */
   private List<String> listIdleTime() {
	  List<String> out = new LinkedList<String>();
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT * FROM idle ORDER BY lastactivity DESC");
		 rs = ps.executeQuery();

		 String output = "";
		 while (rs.next()) {
			if (output.length() > 300) {
			   out.add(output);
			   output = "";
			}
			String temp = UtopiaTime.compareTimes(rs.getTimestamp("lastactivity").getTime());
			temp = temp.replace(" hours, ", "h");
			temp = temp.replace(" minutes, ", "m");
			temp = temp.replace(" seconds", "s");
			output += Colors.BLUE + rs.getString("mainnick") + Colors.OLIVE + temp + Colors.NORMAL + " | ";
		 }
		 if (output.length() > 0) {
			out.add(output);
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   private List<String> listMessages(final String sender) {
	  List<String> out = new LinkedList<String>();
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT * FROM message WHERE sender = ?");
		 ps.setString(1, sender);
		 rs = ps.executeQuery();

		 String output = "";
		 while (rs.next()) {
			if (output.length() > 350) {
			   out.add(output);
			   output = "";
			}
			output += rs.getInt("id") + " to " + rs.getString("recipient") + " - "
				  + rs.getString("message").substring(0, Math.min(rs.getString("message").length(), 7)) + "... | ";
		 }
		 if (output.length() > 0) {
			out.add(output);
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Removes contact info of the specified type for the specified user
    * 
    * @param type
    * @param mainnick
    * @return
    */
   private List<String> removeContactInfo(final String type, final String mainnick) {
	  List<String> out = new LinkedList<String>();
	  PreparedStatement ps = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("UPDATE kdmember SET " + type + " = '' WHERE mainnick = ?");
		 ps.setString(1, mainnick);
		 if (ps.executeUpdate() == 1) {
			out.add("Contact info removed");
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * This method removes contact info that resides in the misc category
    * 
    * @param type
    * @param mainnick
    * @return
    */
   private List<String> removeMiscContactInfo(final String type, final String mainnick) {
	  List<String> out = new LinkedList<String>();
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT misc FROM kdmember WHERE mainnick = ?");
		 ps.setString(1, mainnick);
		 rs = ps.executeQuery();

		 if (rs.next()) {
			String[] misc = rs.getString("misc").split("\n");
			String newMisc = "";
			for (String s : misc) {
			   String[] temp = s.split("\t");
			   if (!temp[0].equalsIgnoreCase(type) && !"".equals(s)) {
				  newMisc += s + "\n";
			   }
			}
			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("UPDATE kdmember SET misc = ? WHERE mainnick = ?");
			ps.setString(1, newMisc);
			ps.setString(2, mainnick);
			int i = ps.executeUpdate();
			if (i > 0) {
			   out.add(type + " removed");
			}
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Removes the user's sms addy
    * 
    * @param user
    * @return
    */
   private List<String> removeSMSAddress(final String user) {
	  List<String> out = new LinkedList<String>();
	  PreparedStatement ps = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection().prepareStatement("DELETE FROM sms WHERE nick = ?");
		 ps.setString(1, user);

		 if (ps.executeUpdate() == 1) {
			out.add("SMS address removed");
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Sets an alarm for the user
    * 
    * @param user
    * @param delay
    * @param message
    * @return
    */
   private List<String> setAlarm(final String user, final Long delay, final String message) {
	  List<String> out = new LinkedList<String>();
	  PreparedStatement ps = null;
	  try {
		 if (delay > 0) {
			delAlarm(user);

			ps = DBConnectionFactory.getConnectionHandler().getConnection().prepareStatement("INSERT INTO alarm VALUES(?,?,?)");
			ps.setString(1, user);
			ps.setTimestamp(2, new Timestamp(GregorianCalendar.getInstance().getTimeInMillis() + delay));
			ps.setString(3, message);
			if (ps.executeUpdate() == 1) {
			   Bot.getInstance().getTimerHandler().addAlarmTimer(new AlarmTimer(user, delay, message));
			   out.add("Alarm set");
			}
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Sets the DST status for the user
    * 
    * @param nick
    * @param stat
    * @return
    */
   private List<String> setDST(final String nick, final String stat) {
	  List<String> out = new LinkedList<String>();
	  int i = 0;
	  String status = stat;
	  if (status.equalsIgnoreCase("on")) {
		 i = 1;
	  } else {
		 status = "off";
	  }
	  PreparedStatement ps = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("UPDATE kdmember SET dst = ? WHERE mainnick = ?");
		 ps.setInt(1, i);
		 ps.setString(2, nick);
		 if (ps.executeUpdate() == 1) {
			out.add("DST status changed to " + status);
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Adds sms notification for the specified type of event
    * 
    * @param user
    * @param type
    * @param isAdd
    * @return
    */
   private List<String> setSMSNotification(final String user, final int type, final boolean isAdd) {
	  List<String> out = new LinkedList<String>();
	  PreparedStatement ps = null;
	  try {
		 if (isAdd) {
			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("INSERT INTO smsnotifications VALUES(?,?)");
		 } else {
			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("DELETE FROM " + "smsnotifications WHERE name = ? AND notificationtype = ?");
		 }
		 ps.setString(1, user);
		 ps.setInt(2, type);
		 if (ps.executeUpdate() == 1) {
			if (isAdd) {
			   out.add("SMS notification set");
			} else {
			   out.add("SMS notification removed");
			}
		 } else {
			if (isAdd) {
			   out.add("SMS notification already set");
			} else {
			   out.add("SMS notification does not exist");
			}
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Removes a nick from the user's nicklist
    * 
    * @param command
    * @param sender
    * @return
    */
   private List<String> unlinkNick(final String nick, final String sender) {
	  List<String> out = new LinkedList<String>();
	  PreparedStatement ps = null;
	  try {
		 if (nick.equals("all")) {
			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("DELETE FROM " + "nickname WHERE mainnick = ? AND name != mainnick");
			ps.setString(1, sender);
		 } else {
			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("DELETE FROM nickname WHERE name = ?");
			ps.setString(1, nick);
		 }

		 if (ps.executeUpdate() > 0) {
			out.add("Nick(s) unlinked");
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }
}
